package com.boge.flowabley;

import org.flowable.engine.*;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SpringBootTest
class FlowableyApplicationTestsFunction {
    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private RuntimeService runtimeService;

    //任务待办的注解
    @Autowired
    private TaskService taskService;


    /**
     * 部署一个流程：固定值分配案例
     */
    @Test
    void deployProcess() {

        Deployment deploy = processEngine.getRepositoryService().createDeployment()
                .addClasspathResource("process/GudingFlowA.bpmn20.xml") // 部署一个流程
                .name("固定值分配案例")
                .deploy();
        System.out.println(deploy.getId()); //010ab143-c5cd-11ef-9f9d-6af5b601192d
    }

    /**
     * 发起一个流程
     */
    @Test
    void startProcess() {
        String processId = "GudingA:2:79abcdb7-c5f0-11ef-8784-fe4995b30266"; //来源于表 ACT_RE_PROCDEF 的 ID_
        String processKey = "GudingFlowA"; //来源于表 ACT_RE_PROCDEF 的 KEY_

        //${myBean.getAssignee()}
        Map<String, Object> variables = new HashMap<>();
        variables.put("processId", processId);
        variables.put("name", "chenll");

        // 第一种启动方式：根据流程定义Id启动 返回的是当前启动的流程实例 ProcessInstance
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processId, variables);

        //variables会记录到： ACT_RU_VARIABLE

        //第二种启动方式： 根据流程定义key启动流程实例 。它会根据 processKey 启动一个流程实例，但默认是启动该 Key 对应的最高版本（VERSION_ 最大值）的流程定义。
//        ProcessInstance processInstanceK = runtimeService.startProcessInstanceByKey(processKey);

        //每次启动后，会在 ACT_RU_TASK 中产生一个待办， NAME、ASSIGNEE_
        //每启动一个流程实例，就会在ACT_HI_PROCINST 流程历史实例表 维护一个记录，然后在 ACT_RU_EXECUTION  产生一个记录流程的分支

        //理解： 流程定义 相当于 类 流程实例 相当于 对象

    }


    /**
     * 启动候选人流程实例
     */
    @Test
    public void runProcess(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 给流程定义中的UEL表达式赋值
        Map<String,Object> variables = new HashMap<>();
        variables.put("candidate1","张三");
        variables.put("candidate2","李四");
        variables.put("candidate3","王五");
        runtimeService.startProcessInstanceById("holiday-candidate:1:4",variables);
    }


    /**
     * 查询候选人
     * 候选人还不是审批人
     * 多个候选人，还需要一个拾取操作，拾取完才是审批人
     * 审批人如果不行操作了
     */
    public void findFlowCandi(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        List<Task> list = taskService.createTaskQuery()
                //.processInstanceId("2501")
                .processDefinitionId("holiday-candidate:1:4")
                .taskCandidateUser("李四")
                .list();
        for (Task task : list) {
            System.out.println("task.getId() = " + task.getId());
            System.out.println("task.getName() = " + task.getName());
        }
    }


    /**
     * 拾取任务
     *    一个候选人拾取了这个任务之后其他的用户就没有办法拾取这个任务了
     *    所以如果一个用户拾取了任务之后又不想处理了，那么可以退还
     */
    @Test
    public void claimTaskCandidate(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                //.processInstanceId("2501")
                .processDefinitionId("holiday-candidate:1:4")
                .taskCandidateUser("李四")
                .singleResult();
        if(task != null){
            // 拾取对应的任务
            taskService.claim(task.getId(),"李四");
            System.out.println("任务拾取成功");
        }
    }

    /**
     * 退还任务
     *    一个候选人拾取了这个任务之后其他的用户就没有办法拾取这个任务了
     *    所以如果一个用户拾取了任务之后又不想处理了，那么可以退还
     */
    @Test
    public void unclaimTaskCandidate(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                //.processInstanceId("2501")
                .processDefinitionId("holiday-candidate:1:4")
                .taskAssignee("张三")
                .singleResult();
        if(task != null){
            // 拾取对应的任务
            taskService.unclaim(task.getId());
            System.out.println("归还拾取成功");
        }
    }


    /**
     * 任务的交接
     *    如果我获取了任务，但是不想执行，那么我可以把这个任务交接给其他的用户
     */
    @Test
    public void taskCandidate(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                //.processInstanceId("2501")
                .processDefinitionId("holiday-candidate:1:4")
                .taskAssignee("李四")
                .singleResult();
        if(task != null){
            // 任务的交接
            taskService.setAssignee(task.getId(),"王五");
            System.out.println("任务交接给了王五");
        }
    }

    /**
     * 完成任务
     */
    @Test
    public void completeTask(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        Task task = taskService.createTaskQuery()
                //.processInstanceId("2501")
                .processDefinitionId("holiday-candidate:1:4")
                .taskAssignee("王五")
                .singleResult();
        if(task != null){
            // 完成任务
            taskService.complete(task.getId());
            System.out.println("完成Task");
        }
    }


    /**
     * 执行运行时变量
     */
    @Test
    void setProcessVariables() {
        String executionId = "0302cd11-c5f1-11ef-9f2b-fe4995b30266";
        runtimeService.setVariable(executionId, "var3", "sdsdfs");
    }

    /**
     * 获取运行时变量
     */
    @Test
    void getProcessVariables() {
        String executionId = "0302cd11-c5f1-11ef-9f2b-fe4995b30266";
        Map<String, Object> variables = runtimeService.getVariables(executionId);
        System.out.println(variables);
        for (var variable : variables.entrySet()) {
            System.out.println(variable.getKey() + "=" + variable.getValue());
        }
    }


    /**
     * 根据用户查询待办
     */
    @Test
    void findFlowByUser() {
        List<Task> list = taskService.createTaskQuery().taskAssignee("lisi ").list();
        for (Task task : list) {
            System.out.println(task.getId());
        }

    }


    /**
     * 挂起流程
     * 激活流程
     */
    @Test
    void suspendActivity() {
        String prcessDefinitionId = "FirstFlow:9:3459536f-c4c7-11ef-bc58-fef18153b082";
        RepositoryService repositoryService = processEngine.getRepositoryService();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(prcessDefinitionId)
                .singleResult();
        // 获取流程定义的状态
        boolean suspended = processDefinition.isSuspended();
        System.out.println("suspended = " + suspended);
        if (suspended) {
            // 表示被挂起,需要被激活
            System.out.println("当前是挂起状态，开始激活流程定义");
            repositoryService.activateProcessDefinitionById(prcessDefinitionId, true, null);
        } else {
            // 表示激活状态
            System.out.println("当前是激活状态，开始挂起流程");
            repositoryService.suspendProcessDefinitionById(prcessDefinitionId, true, null);
        }
    }


    /**
     * 挂起流程实例
     */
    @Test
    void suspendInstance() {
        // 挂起流程实例
        runtimeService.suspendProcessInstanceById("91eb3c1b-c521-11ef-a085-1a99d71cb7b3");
        // 激活流程实例
        //runtimeService.activateProcessInstanceById("91eb3c1b-c521-11ef-a085-1a99d71cb7b3");
    }


}
